package com.bitCoinSystem.javaproject.bitcoinAddress;

import com.alibaba.druid.VERSION;
import com.bitCoinSystem.javaproject.Utils.Base58;
import com.bitCoinSystem.javaproject.Utils.HashUtils;
import com.mchange.v2.c3p0.util.TestUtils;

import java.security.*;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.ECPoint;

/**
 * @author: nilcity
 *  用于生成 比特币地址
 */

public class Address {
    /**
     * java 原生，生成一对密钥，并将 密钥对 对象KeyPair 返回
     * @return
     */

    public  KeyPair GenerateKey(){
        try {
            // key 生成
            KeyPairGenerator generator = KeyPairGenerator.getInstance("EC");
            //  P256  算法
            ECGenParameterSpec secp256k1 = new ECGenParameterSpec("secp256k1");
            generator.initialize(secp256k1);
            // 生成一对密钥
            return generator.generateKeyPair();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidAlgorithmParameterException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 该函数 根据 提供的一对密钥
     * @param keyPair
     * @return  生成的比特币地址
     */

    public  String newAddress(KeyPair keyPair){
        if (keyPair ==null){
            return null;
        }
        ECPublicKey publicKey = (ECPublicKey) keyPair.getPublic();
        //   原始格式公钥 ： 04 + x坐标 （32字节）+ y 坐标（32字节）
        ECPoint point = publicKey.getW();
        byte[] x = point.getAffineX().toByteArray();
        byte[] y = point.getAffineY().toByteArray();
        //  获取原始 格式 的 公钥
        byte[] pubKey = toUncompressPubKey(x,y);

        byte[] sha256 = HashUtils.SHA256(pubKey);
        // 公钥hash
        byte[] pubHash = HashUtils.RIPEMD160(sha256);
        // 添加 前缀
        byte[] version=new byte[1];
        version[0] =0x00;
        byte[] ver_pubhash= new byte[1+pubHash.length];
        System.arraycopy(version,0,ver_pubhash,0,version.length);
        System.arraycopy(pubHash,0,ver_pubhash,1,pubHash.length);

        // 双 Hash 取 校验位
        byte[] hash1 = HashUtils.SHA256(ver_pubhash);
        byte[] hash2 = HashUtils.SHA256(hash1);
        byte[] check=new byte[4];
        System.arraycopy(hash2,0,check,0,4);

        byte[] ver_hash_check =new byte[ver_pubhash.length+check.length];
        System.arraycopy(ver_pubhash,0,ver_hash_check,0,ver_pubhash.length);
        System.arraycopy(check,0,ver_hash_check,ver_pubhash.length,check.length);

        // base 58 编码
        String addre= Base58.encode(ver_hash_check);
        System.out.println(addre);
        return addre;
    }

    /**
     *  根据 X,Y  拼接 生成 原始格式的公钥
     * @param x
     * @param y
     * @return 原始格式的 公钥
     */
    private static  byte[] toUncompressPubKey(byte[] x ,byte[] y){
        byte[] publicKey =new byte[65];
        publicKey[0]=04;
        if (x.length==32){
            System.arraycopy(x,0,publicKey,1,x.length);
        }else{
            System.arraycopy(x,1,publicKey,1,32);
        }
        if (y.length==32){
            System.arraycopy(y,0,publicKey,33,y.length);
        }else{
            System.arraycopy(y,1,publicKey,33,32);
        }
        return publicKey;
    }
}
